---
title: IQueryable的简单封装
sidebar_position: 3
---
# IQueryable的简单封装

## 前言

之前在博客园上看到一个问题

![1](/img/queryquestion.webp)

半年前我也考虑过这些问题,但由于这样那样的问题,没有尝试去解决

后来公司用上了 **abp vnext** ,然后有一部分代码可以这样写

```csharp
protected override IQueryable<Resource> CreateFilteredQuery(GetResourceDto input)
{
    return ReadOnlyRepository.WhereIf(
        input.ParentId.HasValue,
        item => item.ParentId == input.ParentId
    ).WhereIf(
        input.Id.HasValue,
        item => item.Id == input.Id
    );
}
```

用的时候感觉还是有点方便的,但没怎么考虑过如何实现,也就这样一直用着了

看到上面那个问题之后就想起来了这茬儿

## 第一阶段

众所周知,去掉 `if` 的最简单的方式就是用三元 `()?():()`

```csharp
param = string.IsNullOrEmpty(x.CustomerID)
        ?param
        :param.And(x => x.CustomerID == query.CustomerID);
```

讲道理,去掉了 `if` ,但是并没有感觉比用 `if` 的时候好多少

## 第二阶段

众所周知,觉得代码不好看(冗余多)的时候,你应该做点封装了

**一般** 来说,查询时用的应该是 `IQueryable<T> Where(......)`

所以可以对 `IQueryable<T>` 封装一些 **简单** 的扩展方法

```csharp
public static class QueryClass
{
    public static IQueryable<T> WhereIf<T>(this IQueryable<T> query, bool flag, Expression<Func<T, bool>> expression)
    {
        return flag ? query.Where(expression) : query;
    }

    public static IQueryable<T> WhereIf<T>(this IQueryable<T> query, string flag, Expression<Func<T, bool>> expression)
    {
        return string.IsNullOrEmpty(flag) ? query : query.Where(expression);
    }
}
```

用的时候就比较简单了

先定义一下(数据库)实体

```csharp
public class Entity
{
    // 可为空
    public Guid? Id { get; set; }
    // 字符串
    public string Name { get; set; }
    // 值类型
    public int Num { get; set; }
}
```

以上应该是程序里面用到的最多的3种数据类型了(大概)

然后整点数据

```csharp
List<Entity> list = new()
{
    new Entity { Id = Guid.NewGuid(), Name = "2" },
    new Entity { Id = Guid.NewGuid(), Name = "233333" },
    new Entity { Id = Guid.NewGuid(), Name = "233333", Num = 233333 },
    new Entity { Id = Guid.NewGuid(), Name = "233333", Num = 3 },
    new Entity { Id = Guid.NewGuid(), Name = "23" },
    ......
    ......
    new Entity { Id = Guid.NewGuid(), Name = "23", Num = 2333 },
};
```

然后前端传了点数据过来

```csharp
Entity input = new()
{
    Id = null,
    Name = "233",
    Num = 233
};
```

写条件的时候大概就像下面这样

```csharp
var result = list.AsQueryable()
.WhereIf(input.Id.HasValue, item => item.Id == input.Id)
.WhereIf(input.Name, item => item.Name.Contains(input.Name))
.WhereIf(input.Num > 0, item => item.Num > input.Num * 20).ToList();
```

感觉用的时候还是挺方便简洁的

再多做点(过度)封装应该会更好用

## 第三阶段

抱歉我还在第二层......


